Blue Green 배포와 Rolling 배포 비교
Blue Green 배포와 Rolling 배포 비교
Blue/Green은 기존 환경과 새 환경을 동시에 준비한 뒤 traffic destination을 전환한다. 문제가 생기면 이전 환경으로 다시 보내기 쉬운 대신, 전환 기간에 거의 두 벌의 용량과 환경 동기화가 필요하다. Rolling은 기존 instance를 작은 batch로 새 버전으로 교체해 추가 용량을 조절하기 쉽지만 배포 내내 두 버전이 같은 DB·cache·message를 함께 사용한다. 어떤 방식을 쓰든 rollback은 code만 과거로 돌리는 일이 아니다. Schema와 event가 backward compatible하고, 종료 중 instance의 connection이 drain되며, 자동 중단 기준이 있어야 한다.
목차
- #배포 전략은 새 버전을 섞는 방법이다
- #Blue Green 배포의 기본 흐름
- #Rolling 배포의 기본 흐름
- #두 전략의 차이를 한눈에 비교하기
- #무중단을 결정하는 것은 Readiness와 Draining이다
- #Blue Green의 Traffic 전환은 즉시가 아닐 수 있다
- #Rolling의 maxSurge와 maxUnavailable 계산하기
- #신구 버전이 공유하는 DB를 먼저 확인하기
- #Message와 Cache도 버전 호환이 필요하다
- #Rollback이 실제로 가능한 시점
- #Session과 Background Job을 다루는 방법
- #용량과 비용을 계산하기
- #Canary는 두 전략과 다른 축이다
- #자동 중단과 승격 기준 만들기
- #배포 전략 선택 질문
- #실패 시나리오를 포함한 검증
- #구현 체크리스트
- #마무리
- #관련 노트
- #참고 자료
배포 전략은 새 버전을 섞는 방법이다
배포는 binary를 server에 복사하는 동작으로 끝나지 않는다. 사용자의 traffic을 어떤 비율과 순서로 새 version에 연결할지 결정해야 한다.
현재 상태: v1 instance 4개가 traffic 100% 처리
목표 상태: v2 instance 4개가 traffic 100% 처리
Blue/Green과 Rolling의 핵심 차이는 교체 단위다.
flowchart LR
A[v1 fleet]
B[v2 fleet]
C[Traffic router]
A --> C
B --> C- Blue/Green은 fleet 단위로 새 환경을 준비하고 router가 가리키는 대상을 바꾼다.
- Rolling은 한 fleet 안의 instance를 batch 단위로 차례로 바꾼다.
둘 다 downtime을 줄일 수 있지만 “배포 명령이 성공했다”는 사실만으로 무중단이 보장되지는 않는다. 새 instance가 준비되기 전에 traffic을 받거나, 기존 instance가 요청 처리 중 종료되면 오류가 생긴다.
Blue Green 배포의 기본 흐름
현재 production인 blue와 별도의 green 환경을 만든다.
sequenceDiagram
participant P as Pipeline
participant B as Blue v1
participant G as Green v2
participant R as Router
P->>G: Provision and deploy
P->>G: Smoke test
P->>R: Shift traffic to green
R->>G: New requests
P->>G: Observe
P->>B: Decommission after rollback window전환 전 green에는 production과 동일한 configuration contract, network policy, secret, autoscaling 기준이 있어야 한다. “동일한 환경”은 instance ID까지 같다는 뜻이 아니라 runtime 조건과 의존성이 동등하다는 뜻이다.
Blue/Green의 장점은 이전 환경을 그대로 남길 수 있다는 점이다.
정상: router → green v2
문제: router → blue v1
하지만 blue가 rollback target이 되려면 전환 이후에 생긴 데이터와 schema를 여전히 이해할 수 있어야 한다. Code environment만 보존했다고 rollback이 가능한 것은 아니다.
Rolling 배포의 기본 흐름
Rolling은 일부 instance를 제거하고 새 version으로 채우는 과정을 반복한다.
1단계 v1 v1 v1 v1
2단계 v1 v1 v1 v2
3단계 v1 v1 v2 v2
4단계 v1 v2 v2 v2
5단계 v2 v2 v2 v2
Kubernetes Deployment를 예로 들 수 있다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: sample-api
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
minReadySeconds: 15
progressDeadlineSeconds: 600
maxUnavailable: 0은 업데이트 중 desired replica보다 ready instance가 줄지 않게 하고 maxSurge: 1은 하나의 추가 Pod를 허용한다. Cluster에 추가 자원이 없으면 새 Pod가 schedule되지 않아 rollout이 멈출 수 있다.
Replica와 시간은 가상 값이다. 실제 traffic과 startup time, cluster capacity를 기준으로 정한다.
두 전략의 차이를 한눈에 비교하기
| 기준 | Blue/Green | Rolling |
|---|---|---|
| 교체 단위 | 환경 전체 | instance batch |
| 신구 공존 | 전환 전후 두 환경 | rollout 동안 같은 service |
| 추가 용량 | 최대 거의 100% | maxSurge만큼 조절 |
| Code rollback | traffic 재전환이 빠를 수 있음 | 이전 version을 다시 rollout |
| 사전 검증 | Green을 production traffic 전 test | 새 batch readiness 중심 |
| Blast radius | 전환 비율에 따라 큼 | batch 크기로 제한 |
| 환경 drift 위험 | Blue/Green 설정 차이 | 같은 template이면 상대적으로 작음 |
| Stateful data | 두 환경 동기화가 어려움 | 공유 store 호환이 필수 |
표의 우열은 workload에 따라 달라진다. 예를 들어 traffic router가 하나의 환경만 0% 또는 100%로 전환한다면 Blue/Green의 첫 production traffic blast radius가 크다. Weight 전환을 지원하면 점진적으로 줄일 수 있다.
무중단을 결정하는 것은 Readiness와 Draining이다
새 instance는 process가 실행 중이라는 이유만으로 traffic을 받으면 안 된다. Configuration load, DB connection, cache warm-up처럼 요청 처리에 필요한 준비가 끝나야 한다.
readinessProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 3
기존 instance를 제거할 때도 endpoint 목록에서 빠지는 것과 실제 load balancer 전파에는 간격이 있다. Application은 종료 signal을 받으면 readiness를 내리고 새 요청을 거부하며 진행 중 요청을 drain한다.
sequenceDiagram
participant O as Orchestrator
participant P as Old instance
participant L as Load balancer
O->>P: Termination begins
P->>P: readiness false
O->>L: remove endpoint
L--xP: stop new traffic
P->>P: finish in-flight requests
P-->>O: exit종료 흐름은 컨테이너의 PID 1 문제와 시그널 처리와 연결된다.
Blue Green의 Traffic 전환은 즉시가 아닐 수 있다
Load balancer target group을 바꾸는 방식과 DNS record를 바꾸는 방식은 rollback 속도가 다르다.
DNS는 TTL과 client cache 때문에 일부 client가 이전 endpoint를 계속 사용할 수 있다.
00:00 DNS green으로 변경
00:10 일부 client green
02:00 오래 cache한 client blue
이 기간에는 Blue와 Green이 모두 실제 production traffic을 받을 수 있다. Blue를 즉시 종료하면 stale DNS client가 실패한다.
Router 수준의 target 전환도 existing TCP/WebSocket connection은 이전 environment에 남을 수 있다. 다음을 확인한다.
- 새 connection만 green으로 가는가
- 기존 keep-alive와 WebSocket은 언제 끝나는가
- Mobile client의 DNS cache가 얼마나 지속되는가
- Rollback 시 green의 진행 중 request를 어떻게 drain하는가
- Blue를 몇 시간 또는 며칠 보존할 것인가
Control plane의 routing 설정과 실제 client connection이 동시에 바뀐다고 가정하지 않는다.
Rolling의 maxSurge와 maxUnavailable 계산하기
Replica 10개에서 maxUnavailable: 20%, maxSurge: 30%라면 Kubernetes는 percentage rounding 규칙에 따라 unavailable 허용량과 추가 Pod 수를 계산한다. 작은 replica 수에서는 percentage 하나가 큰 비율 차이를 만든다.
| 설정 | 가용성 | 추가 자원 | 속도 |
|---|---|---|---|
| unavailable 0, surge 1 | 높음 | 1개 필요 | 비교적 느림 |
| unavailable 1, surge 0 | 용량 감소 | 추가 없음 | workload에 따라 |
| unavailable 25%, surge 25% | 균형 | 일부 필요 | 비교적 빠름 |
새 version의 CPU/memory가 늘었다면 기존 capacity 계산으로 surge Pod가 schedule되지 않을 수 있다. 반대로 autoscaler가 반응하기 전에 많은 Pod를 띄우면 resource pressure가 생긴다.
minReadySeconds는 잠깐 readiness를 통과했다가 바로 죽는 Pod를 안정된 것으로 너무 빨리 보지 않게 한다. progressDeadlineSeconds는 rollout 진행 정체를 상태로 표시하지만 그 자체가 모든 platform에서 자동 rollback을 수행한다고 가정해서는 안 된다. Pipeline이 상태를 읽고 중단·rollback하는 정책이 필요하다.
신구 버전이 공유하는 DB를 먼저 확인하기
Rolling 동안 v1과 v2는 같은 DB에 동시에 query한다. Blue/Green도 DB를 환경 밖에서 공유하는 구성이 흔하다.
Breaking schema 변경을 code와 한 번에 배포하면 한 버전이 깨진다.
-- 위험한 예: v1이 아직 old_name을 읽고 있다.
ALTER TABLE customer
DROP COLUMN old_name;
호환 기간을 둔다.
1. 새 column 추가
2. v1과 v2가 공존 가능한 write/read 배포
3. backfill과 검증
4. v2로 완전 전환
5. rollback window 종료
6. old column 제거
Blue로 traffic을 되돌려도 v2가 저장한 새 enum, 긴 값, 새로운 state를 v1이 읽지 못하면 rollback이 실패한다. 이 문제는 무중단 배포에서 DB 마이그레이션 순서에서 확장한다.
Message와 Cache도 버전 호환이 필요하다
배포 중 v2 producer가 만든 event를 v1 consumer가 받을 수 있다.
{
"eventType": "ORDER_CONFIRMED",
"schemaVersion": 2,
"orderId": "order_demo_42",
"channel": "mobile"
}
새 field를 추가하고 구버전이 unknown field를 무시할 수 있다면 호환되기 쉽다. Required field 삭제나 의미 변경은 어렵다.
Cache도 serialization version이 다르면 역직렬화에 실패할 수 있다.
cache key = profile:v2:<user-id>
Versioned key로 분리하거나 두 version이 읽을 수 있는 format을 사용한다. Deploy 때 cache 전체 삭제에 의존하면 thundering herd와 DB 부하가 생길 수 있다.
Rollback이 실제로 가능한 시점
Rollback은 다음 세 층을 되돌릴 수 있어야 한다.
| 층 | 질문 |
|---|---|
| Traffic | 이전 instance로 다시 보낼 수 있는가 |
| Code/config | 이전 artifact와 config가 남아 있는가 |
| Data/protocol | 이전 code가 현재 data와 event를 이해하는가 |
Blue/Green의 traffic rollback은 router 변경으로 빠를 수 있다. Rolling rollback은 이전 image를 다시 batch 배포하므로 시간이 걸린다. 하지만 data compatibility가 깨졌다면 둘 다 안전하지 않다.
Rollback 가능 시점을 명시한다.
T0 green/rolling 시작
T1 traffic 전환 완료
T2 관찰 window
T3 backward compatibility 종료
T4 destructive migration
T3 전에는 code rollback이 가능해야 한다. T4 뒤에는 restore나 forward fix가 필요할 수 있다. Pipeline과 runbook에 이 경계를 기록한다.
전환 이후 정상 사용자가 만든 data를 과거 snapshot으로 되돌리면 유실된다. Schema rollback과 data recovery를 분리한다.
Session과 Background Job을 다루는 방법
In-memory session을 instance에 저장하면 Rolling 교체와 Blue/Green 전환 때 사용자가 logout될 수 있다. Shared session store 또는 stateless token을 사용하거나 session affinity의 전환 영향을 설계한다.
WebSocket은 connection이 오래 유지된다.
HTTP short request → 수 초 안에 drain
WebSocket session → 수 시간 지속 가능
강제 종료 deadline, reconnect protocol, client backoff, resume token이 필요하다.
Background worker는 새/구 version이 같은 queue를 소비할 수 있다. Job payload schema와 side effect가 호환되어야 하며 중복 처리에 대비한다.
async function handleJob(job: JobEnvelope) {
if (!supportedVersions.has(job.schemaVersion)) {
await deadLetter(job, "unsupported_schema");
return;
}
await processIdempotently(job.id, () => execute(job));
}
가상 예시다. Deploy 중 worker concurrency를 줄이거나 queue를 version별로 분리할 필요가 있는지 workload에 따라 정한다.
용량과 비용을 계산하기
Blue/Green은 전환 순간 양쪽 environment가 production scale에 가까울 수 있다.
평상시 100 instance
전환 시 blue 100 + green 100 + 검증 traffic 여유
Rolling은 maxSurge만큼 추가하지만 update 중 ready capacity와 실제 throughput이 같지는 않다. 새 version의 startup CPU spike와 cache cold miss가 있다.
Capacity 계산에 포함할 항목:
- Application instance CPU/memory
- Load balancer target과 connection limit
- DB connection pool 합계
- Cache miss로 인한 backend 부하
- Message consumer 동시성
- Autoscaler 관측 지연
Blue와 Green이 각각 DB pool 100개를 열면 전환 중 connection이 두 배가 된다. Green warm-up을 production dependency에 그대로 흘려보내기 전에 제한한다.
Canary는 두 전략과 다른 축이다
Canary는 소량 traffic으로 위험을 제한하는 release 방식이다. Blue/Green의 green environment에 1% traffic을 먼저 보낼 수도 있고 Rolling의 첫 batch를 canary로 오래 관찰할 수도 있다.
flowchart LR
A[New version]
B[1 percent]
C[10 percent]
D[50 percent]
E[100 percent]
A --> B --> C --> D --> E단순 instance 비율이 user traffic 비율과 같지 않을 수 있다. Sticky session, regional traffic, hot shard 때문에 canary가 특정 사용자군만 받을 수 있다.
Canary 분석은 sample size와 business metric을 고려한다. Error rate가 낮아도 checkout conversion이나 processing latency가 나빠질 수 있다.
자동 중단과 승격 기준 만들기
Pipeline의 “green healthy”는 health endpoint 한 번 성공보다 강해야 한다.
| 단계 | 확인 |
|---|---|
| 기동 | 모든 instance ready, crash loop 없음 |
| Smoke | 핵심 read/write path 성공 |
| 기술 지표 | error rate, latency, saturation |
| 업무 지표 | 주문 성공률, 결제 승인률 |
| 호환성 | 구버전 consumer와 DB query |
| 보안 | image provenance와 scan gate |
가상 기준을 configuration으로 표현할 수 있다.
promotion:
observationWindow: 15m
minimumRequests: 10000
gates:
errorRateIncrease: "< 0.2%"
p95LatencyIncrease: "< 15%"
crashLoopCount: 0
실제 threshold는 baseline 변동과 SLO에서 정한다. Traffic이 적어 sample이 부족하면 자동 성공으로 처리할지, 관찰 시간을 늘릴지 결정한다.
Rollback signal도 사용자 영향 전에 탐지할 수 있어야 한다.
- Readiness 실패율
- Deployment progress timeout
- 새 version별 5xx
- DB lock과 connection saturation
- Queue lag와 retry
- Client crash
배포 전략 선택 질문
Blue/Green이 어울리는 경우:
- 거의 동일한 두 환경을 자동 생성할 수 있다.
- 빠른 traffic rollback의 가치가 크다.
- 전환 중 추가 용량을 감당할 수 있다.
- Shared data가 양쪽 code와 호환된다.
- Environment drift를 지속적으로 검증할 수 있다.
Rolling이 어울리는 경우:
- 추가 capacity를 제한해야 한다.
- Instance가 대체 가능하고 startup이 안정적이다.
- 신구 version 공존이 충분히 검증됐다.
- Batch별 관측과 중단이 가능하다.
- 이전 version 재-rollout 시간을 감당할 수 있다.
둘 중 하나를 조직 표준으로 정하더라도 stateful worker, edge server, mobile backend처럼 workload 특성에 따라 예외가 생긴다.
실패 시나리오를 포함한 검증
구현 체크리스트
마무리
Blue/Green과 Rolling은 이름보다 신구 version을 어떤 범위와 시간 동안 공존시키는지가 중요하다. Blue/Green은 환경을 병렬로 준비해 traffic을 바꾸므로 code rollback이 빠를 수 있지만 이중 용량과 환경 동등성이 필요하다.
Rolling은 instance를 작은 batch로 교체해 추가 자원을 조절할 수 있지만 rollout 내내 두 version이 같은 DB, event, cache를 사용한다. maxSurge와 maxUnavailable은 availability와 capacity 사이의 정책이다.
두 전략 모두 readiness와 connection draining이 없으면 무중단이 아니다. 또한 router만 되돌린다고 rollback이 완성되지 않는다. 새 version이 기록한 data를 이전 version이 읽을 수 있어야 하고 destructive migration은 rollback window 뒤로 미뤄야 한다.
결국 배포 전략은 infrastructure 옵션 하나가 아니라 호환성, 용량, 관측, 중단 기준, 복구 시간을 함께 정하는 운영 계약이다.